#include "Hmac.h"
#include <openssl/md5.h>
#include <string.h>
#define TAMANIO_BLOQUE_MD5 64

std::string Hmac::getDigest(const std::string& msj, const std::string& clave)
{
	unsigned char claveMD5[TAMANIO_BLOQUE_MD5];
	memset(claveMD5, 0, TAMANIO_BLOQUE_MD5);//relleno con ceros el digestResult

	//si la longitud de la clave es mayor al tamanio del bloque
	//se acorta reseteando la clave     claveMD5=MD5(claveMD5)
	if(clave.length() > TAMANIO_BLOQUE_MD5){
		unsigned char digestTemporal[TAMANIO_DIGEST_MD5];
		MD5_CTX estructuraMD5Temporal;

		MD5_Init(&estructuraMD5Temporal);
		MD5_Update(&estructuraMD5Temporal, clave.c_str(), clave.length());
		MD5_Final(digestTemporal, &estructuraMD5Temporal);
		
		memcpy(claveMD5, digestTemporal, TAMANIO_DIGEST_MD5); //copio el digestTemporal al claveMD5
	}
	else{
		memcpy(claveMD5, clave.c_str(), clave.length()); //copio la clave al claveMD5
	}
		memcpy(claveMD5, clave.c_str(), clave.length()); //copio la clave al claveMD5

	

	unsigned char ipad[TAMANIO_BLOQUE_MD5];
	unsigned char opad[TAMANIO_BLOQUE_MD5];

	//cargo el ipad y el opad
	memset(ipad, 0x36, sizeof(ipad));
	memset(opad, 0x5c, sizeof(opad));


	//realizo el XOR
	for (unsigned i=0; i<TAMANIO_BLOQUE_MD5; i++) {
		ipad[i] ^= claveMD5[i];
		opad[i] ^= claveMD5[i];
	}

	//realizo el inner MD5
	unsigned char digestResult[TAMANIO_DIGEST_MD5];
	MD5_CTX estructuraMD5;

	MD5_Init(&estructuraMD5);
	MD5_Update(&estructuraMD5, ipad, TAMANIO_BLOQUE_MD5);
	MD5_Update(&estructuraMD5, msj.c_str(), msj.length());
	MD5_Final(digestResult, &estructuraMD5);
	
	//realizo el outer MD5
	MD5_Init(&estructuraMD5);
	MD5_Update(&estructuraMD5, opad, TAMANIO_BLOQUE_MD5);
	MD5_Update(&estructuraMD5, digestResult, TAMANIO_DIGEST_MD5);
	MD5_Final(digestResult, &estructuraMD5);

	std::string digest;
	digest.append((const char*)digestResult, TAMANIO_DIGEST_MD5);

	return digest;
}

